#pragma once 

/* 消息表的ODB映射操作 */

#include "mysql.hpp"
#include "message.hxx"
#include "message-odb.hxx"


namespace ChatSystem
{
    //消息表的ODB操作

    class MessageTable
    {
    public:
        using ptr = std::shared_ptr<MessageTable>;
        MessageTable(const std::shared_ptr<odb::core::database>& db)
        :_db(db)
        {}

        ~MessageTable()
        {}

        //新增数据
        bool insert(Message& msg)
        {
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //获取对象开启事务
                odb::transaction trans(_db->begin());
                _db->persist(msg);  //在 persist 中会修改 msg对象，所以参数不能设置为const
                //提交事务
                trans.commit();
            }
            catch(const std::exception& e)
            {
                LOG_ERROR("新增消息失败, {} : {}!", msg.message_id(), e.what());
                return false;
            }
            return true;   
        }

        //删除消息表中的数据---在删除会话或者解除好友关系的时候就删除对应的消息表中的数据
        bool remove(const std::string& chat_session_id)
        {
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //获取对象开启事务
                odb::transaction trans(_db->begin());
                //1. 先查询
                typedef odb::query<Message> query;
                typedef odb::result<Message> result;
                _db->erase_query<Message>(query::chat_session_id == chat_session_id);
                //提交事务
                trans.commit();
            }
            catch(const std::exception& e)
            {
                LOG_ERROR("删除 {} 会话的所有消息失败, {}!", chat_session_id, e.what());
                return false;
            }
            return true;  
        }

        //获取指定会话的最近N条消息---这个返回出来的消息产生时间最早的在末尾，产生时间最近的在头部；
        std::vector<Message> recent(const std::string& chat_session_id, int count)
        {
            std::vector<Message> res;
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //3. 获取事务操作对象，开启事务
                odb::transaction trans(_db->begin());
                //4. 数据操作
                typedef odb::query<Message> query;
                typedef odb::result<Message> result;
                //本次查询是以chat_session_id为过滤条件，然后进行以时间字段进行逆序，通过limit分页
                //chat_session_id='xx' order by create_time desc limit count
                std::stringstream cond;
                cond << "chat_session_id='" << chat_session_id << "' ";
                cond << "order by create_time desc limit " << count;
                result r(_db->query<Message>(cond.str()));  //_db->query<xxx>在构造的时候会自动的在查询条件前面加上 where ；
                for(auto it = r.begin(); it != r.end(); ++it)
                {
                    res.push_back(*it);
                }
                //将消息进行逆序，保证显示的消息时间是从小到大，也就是从最早到最近
                std::reverse(res.begin(), res.end());
                //5. 提交事务
                trans.commit();
            }
            catch(std::exception& e)
            {
                LOG_ERROR("获取 {} 会话的最近 {} 条消息失败, {}", chat_session_id, count, e.what());
            }
            return res;
        }

        //获取指定会话某个时间段的消息
        std::vector<Message> range(const std::string& chat_session_id, const boost::posix_time::ptime& start_time, 
            const boost::posix_time::ptime& end_time)
        {
            std::vector<Message> res;
            //对时间段进行判断，看时间是否合法
            if(start_time.is_not_a_date_time() || end_time.is_not_a_date_time() || start_time > end_time  )
            {
                 LOG_ERROR("指定的时间段：{} - {} 不合理!", 
                    boost::posix_time::to_simple_string(start_time), 
                    boost::posix_time::to_simple_string(end_time));
                return res;
            }
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //3. 获取事务操作对象，开启事务
                odb::transaction trans(_db->begin());
                //4. 数据操作
                typedef odb::query<Message> query;
                typedef odb::result<Message> result;
                //本次查询是以chat_session_id 和 指定时间段 为过滤条件，然后进行查找
                result r(_db->query<Message>(query::chat_session_id == chat_session_id 
                    && query::create_time >= start_time
                    && query::create_time <= end_time));  
                for(auto it = r.begin(); it != r.end(); ++it)
                {
                    res.push_back(*it);
                }
                //5. 提交事务
                trans.commit();
            }
            catch(std::exception& e)
            {
                LOG_ERROR("获取 {} 会话指定时间段：{} - {} 的消息失败, {}", chat_session_id, 
                    boost::posix_time::to_simple_string(start_time), 
                    boost::posix_time::to_simple_string(end_time), e.what());
            }
            return res;
        }
    private:
        std::shared_ptr<odb::core::database> _db;   //对数据库的操作都是通过db来操作的---数据库操作句柄
    };

}